package com.easychat.service.impl;

import java.util.Date;
import java.util.List;

import javax.annotation.Resource;

import com.easychat.entity.constants.Constants;
import com.easychat.entity.dto.MessageSendDTO;
import com.easychat.entity.dto.SysSettingDto;
import com.easychat.entity.dto.TokenUserInfoDto;
import com.easychat.entity.dto.UserContactSearchResultDTO;
import com.easychat.entity.enums.*;
import com.easychat.entity.po.*;
import com.easychat.entity.query.*;
import com.easychat.exception.BusinessException;
import com.easychat.mappers.*;
import com.easychat.service.UserContactApplyService;
import com.easychat.utils.CopyTools;
import com.easychat.utils.RedisUtil;
import com.easychat.websocket.ChannelContextUtils;
import com.easychat.websocket.MessageHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import com.easychat.entity.vo.PaginationResultVO;
import com.easychat.service.UserContactService;
import com.easychat.utils.StringTools;
import org.springframework.transaction.annotation.Transactional;


/**
 *  业务接口实现
 */
@Service("userContactService")
public class UserContactServiceImpl implements UserContactService {

	@Resource
	private UserContactMapper<UserContact, UserContactQuery> userContactMapper;

	@Resource
	private UserInfoMapper<UserInfo, UserInfoQuery> userInfoMapper;

	@Resource
	private ChatSessionMapper<ChatSession, ChatSessionQuery> chatSessionMapper;

	@Resource
	private ChatSessionUserMapper<ChatSessionUser, ChatSessionUserQuery> chatSessionUserMapper;

	@Resource
	private ChatMessageMapper<ChatMessage, ChatMessageQuery> chatMessageMapper;

	@Resource
	private GroupInfoMapper<GroupInfo, GroupInfoQuery> groupInfoMapper;

	@Resource
	private UserContactApplyMapper<UserContactApply, UserContactApplyQuery> userContactApplyMapper;

	@Resource
	private UserContactApplyService userContactApplyServicel;

	@Resource
	private MessageHandler messageHandler;

    @Autowired
    private RedisUtil redisUtil;
    @Qualifier("redisTemplate")
    @Autowired
    private RedisTemplate redisTemplate;

	/**
	 * 根据条件查询列表
	 */
	@Override
	public List<UserContact> findListByParam(UserContactQuery param) {
		return this.userContactMapper.selectList(param);
	}

	/**
	 * 根据条件查询列表
	 */
	@Override
	public Integer findCountByParam(UserContactQuery param) {
		return this.userContactMapper.selectCount(param);
	}

	/**
	 * 分页查询方法
	 */
	@Override
	public PaginationResultVO<UserContact> findListByPage(UserContactQuery param) {
		int count = this.findCountByParam(param);
		int pageSize = param.getPageSize() == null ? PageSize.SIZE15.getSize() : param.getPageSize();

		SimplePage page = new SimplePage(param.getPageNo(), count, pageSize);
		param.setSimplePage(page);
		List<UserContact> list = this.findListByParam(param);
		PaginationResultVO<UserContact> result = new PaginationResultVO(count, page.getPageSize(), page.getPageNo(), page.getPageTotal(), list);
		return result;
	}

	/**
	 * 新增
	 */
	@Override
	public Integer add(UserContact bean) {
		return this.userContactMapper.insert(bean);
	}

	/**
	 * 批量新增
	 */
	@Override
	public Integer addBatch(List<UserContact> listBean) {
		if (listBean == null || listBean.isEmpty()) {
			return 0;
		}
		return this.userContactMapper.insertBatch(listBean);
	}

	/**
	 * 批量新增或者修改
	 */
	@Override
	public Integer addOrUpdateBatch(List<UserContact> listBean) {
		if (listBean == null || listBean.isEmpty()) {
			return 0;
		}
		return this.userContactMapper.insertOrUpdateBatch(listBean);
	}

	/**
	 * 多条件更新
	 */
	@Override
	public Integer updateByParam(UserContact bean, UserContactQuery param) {
		StringTools.checkParam(param);
		return this.userContactMapper.updateByParam(bean, param);
	}

	/**
	 * 多条件删除
	 */
	@Override
	public Integer deleteByParam(UserContactQuery param) {
		StringTools.checkParam(param);
		return this.userContactMapper.deleteByParam(param);
	}

	/**
	 * 根据UserIdAndContactId获取对象
	 */
	@Override
	public UserContact getUserContactByUserIdAndContactId(String userId, String contactId) {
		return this.userContactMapper.selectByUserIdAndContactId(userId, contactId);
	}

	/**
	 * 根据UserIdAndContactId修改
	 */
	@Override
	public Integer updateUserContactByUserIdAndContactId(UserContact bean, String userId, String contactId) {
		return this.userContactMapper.updateByUserIdAndContactId(bean, userId, contactId);
	}

	/**
	 * 根据UserIdAndContactId删除
	 */
	@Override
	public Integer deleteUserContactByUserIdAndContactId(String userId, String contactId) {
		return this.userContactMapper.deleteByUserIdAndContactId(userId, contactId);
	}

	@Override
	public List<UserContact> selectUserContactListByGroupId(String groupId) {
		return userContactMapper.selectUserContactListByGroupId(groupId);
	}

	@Override
	public UserContactSearchResultDTO searchContact(String userId, String contactId) {
		UserContactTypeEnum typeEnum = UserContactTypeEnum.getByPrefix(contactId);
		if (null == typeEnum) {
			return null;
		}
		UserContactSearchResultDTO resultDTO = new UserContactSearchResultDTO();
		switch (typeEnum) {
			case USER:
				UserInfo userInfo = userInfoMapper.selectByUserId(contactId);
				if (null == userInfo) {
					return null;
				}
				resultDTO = CopyTools.copy(userInfo, UserContactSearchResultDTO.class);
				break;
			case GROUP:
				GroupInfo groupInfo = groupInfoMapper.selectByGroupId(contactId);
				if (null == groupInfo) {
					return null;
				}
				resultDTO.setNickName(groupInfo.getGroupName());
				break;
		}
		resultDTO.setContactType(typeEnum.toString());
		resultDTO.setContactId(contactId);

		// 自己搜自己
		if (userId.equals(contactId)) {
			resultDTO.setStatus(UserContactStatusEnum.FRIEND.getStatus());
			return resultDTO;
		}

		// 查询是否是好友
		UserContact userContact = userContactMapper.selectByUserIdAndContactId(userId, contactId);
		resultDTO.setStatus(userContact == null ? null : userContact.getStatus());

		return resultDTO;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public Integer applyAdd(TokenUserInfoDto tokenUserInfoDto, String contactId, String applyInfo) {
		UserContactTypeEnum typeEnum = UserContactTypeEnum.getByPrefix(contactId);
		if (null == typeEnum) {
			throw new BusinessException(ResponseCodeEnum.CODE_600);
		}
		String applyUserId = tokenUserInfoDto.getUserId();

		applyInfo = StringTools.isEmpty(applyInfo) ? String.format(Constants.APPLY_INFO_TEMPLATE, tokenUserInfoDto.getNickName()) : applyInfo;
		long currentTime = System.currentTimeMillis();
		Integer joinType = null;
		String receiveUserId = contactId;

		// 查询对方好友是否已经添加，如果已经拉黑，无法添加
		UserContact userContact = userContactMapper.selectByUserIdAndContactId(applyUserId, contactId);
	    if (userContact != null && userContact.getStatus().equals(UserContactStatusEnum.BLACKLIST_BE.getStatus())
		|| userContact != null && userContact.getStatus().equals(UserContactStatusEnum.BLACKLIST_BE_FIRST.getStatus())) {
			throw new BusinessException("对方已拉黑，无法添加");
		}

		// 如果是群
		if (UserContactTypeEnum.GROUP.equals(typeEnum)) {
			GroupInfo groupInfo = groupInfoMapper.selectByGroupId(contactId);
			if (groupInfo == null || groupInfo.getStatus().equals(GroupStatusEnum.DISBAND.getStatus())) {
				throw new BusinessException("群已解散或不存在");
			}
			// 群主接收消息
			receiveUserId = groupInfo.getGroupOwnerId();
			joinType = groupInfo.getJoinType();
		} else {
			UserInfo userInfo = userInfoMapper.selectByUserId(contactId);
			if (userInfo == null) {
				throw new BusinessException("用户不存在");
			}
			joinType = userInfo.getJoinType();
		}
		// 按照joinType分条件, 0: 直接添加, 1: 等待验证
		if (0 == joinType) {
			userContactApplyServicel.addContact(applyUserId, receiveUserId, contactId, typeEnum.getType(), applyInfo);
			return joinType;
		}

		UserContactApply dbApply = userContactApplyMapper.selectByApplyUserIdAndReceiveUserIdAndContactId(applyUserId, receiveUserId, contactId);

		if (dbApply == null) {
			UserContactApply apply = new UserContactApply();
			apply.setApplyUserId(applyUserId);
			apply.setContactType(typeEnum.getType());
			apply.setReceiveUserId(receiveUserId);
			apply.setLastApplyTime(currentTime);
			apply.setContactId(contactId);
			apply.setStatus(UserContactApplyStatusEnum.INIT.getStatus());
			apply.setApplyInfo(applyInfo);
			userContactApplyMapper.insert(apply);
		} else {
			// 更新状态
			UserContactApply apply = new UserContactApply();
			apply.setStatus(UserContactApplyStatusEnum.INIT.getStatus());
			apply.setLastApplyTime(currentTime);
			apply.setApplyInfo(applyInfo);
			userContactApplyMapper.updateByApplyId(apply, apply.getApplyId());
		}

		if (dbApply == null || !UserContactApplyStatusEnum.INIT.getStatus().equals(dbApply.getStatus())) {
			MessageSendDTO messageSendDTO = new MessageSendDTO();
			messageSendDTO.setMessageType(MessageTypeEnum.CONTACT_APPLY.getType());
			messageSendDTO.setMessageContent(applyInfo);
			messageSendDTO.setContactId(receiveUserId);
			messageHandler.sendMessage(messageSendDTO);
		}

		return joinType;
	}

	@Override
	public List<UserContact> selectUserContactList(String userId, Integer contactType) {
		return userContactMapper.selectUserContactList(userId, contactType);
	}

	@Override
	public List<UserContact> selectGroupContactList(String userId, Integer type) {
		return userContactMapper.selectGroupContactList(userId, type);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void removeUserContact(String userId, String contactId, UserContactStatusEnum statusEnum) {
		// 移除好友
		UserContact userContact = new UserContact();
		userContact.setStatus(statusEnum.getStatus());
		userContactMapper.updateByUserIdAndContactId(userContact, userId, contactId);

		// 将好友中移除自己
		UserContact friendContact = new UserContact();
		if (UserContactStatusEnum.DEL.equals(statusEnum)) {
			friendContact.setStatus(UserContactStatusEnum.DEL_BE.getStatus());
		} else if (UserContactStatusEnum.BLACKLIST.equals(statusEnum)) {
			friendContact.setStatus(UserContactStatusEnum.BLACKLIST_BE.getStatus());
		}
		userContactMapper.updateByUserIdAndContactId(friendContact, contactId, userId);

		redisTemplate.opsForList().remove(Constants.REDIS_KEY_USER_CONTACT + contactId, 0, userId);
		redisTemplate.opsForList().remove(Constants.REDIS_KEY_USER_CONTACT + userId, 0, contactId);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void addContactRobot(String userId) {
		Date curDate = new Date();
		SysSettingDto sysSetting = redisUtil.getSysSetting();
		String robotUid = sysSetting.getRobotUid();
		String robotNickName = sysSetting.getRobotNickName();
		String sendMessage = sysSetting.getRobotWelcome();
		sendMessage = StringTools.clearnHtmlTag(sendMessage);
		// 增加机器人好友
		UserContact userContact = new UserContact();
		userContact.setUserId(userId);
		userContact.setContactId(robotUid);
		userContact.setContactType(UserContactTypeEnum.USER.getType());
		userContact.setCreateTime(curDate);
		userContact.setLastUpdateTime(curDate);
		userContact.setStatus(UserContactStatusEnum.FRIEND.getStatus());
		userContactMapper.insert(userContact);
		// 增加会话信息
		String sessionId = StringTools.getChatSessionId4User(new String[] {userId, robotUid});
		ChatSession chatSession = new ChatSession();
		chatSession.setSessionId(sessionId);
		chatSession.setLastMessage(sendMessage);
		chatSession.setLastReceiveTime(curDate.getTime());
		chatSessionMapper.insert(chatSession);

		// 增加会话人信息
		ChatSessionUser chatSessionUser = new ChatSessionUser();
		chatSessionUser.setUserId(userId);
		chatSessionUser.setSessionId(sessionId);
		chatSessionUser.setContactId(robotUid);
		chatSessionUser.setContactName(robotNickName);
		chatSessionUserMapper.insert(chatSessionUser);

		// 增加聊天消息
		ChatMessage chatMessage = new ChatMessage();
		chatMessage.setSessionId(sessionId);
		chatMessage.setMessageType(MessageTypeEnum.CHAT.getType());
		chatMessage.setMessageContent(sendMessage);
		chatMessage.setSendUserId(robotUid);
		chatMessage.setSendUserNickName(robotNickName);
		chatMessage.setSendTime(curDate.getTime());
		chatMessage.setContactId(userId);
		chatMessage.setContactType(UserContactTypeEnum.USER.getType());
		chatMessage.setStatus(MessageStatusEnum.SENDED.getStatus());
		chatMessageMapper.insert(chatMessage);
		
	}
}